/*
 * @Author: '浪川' '1214391613@qq.com'
 * @Date: 2025-09-22 12:02:52
 * @LastEditors: '浪川' '1214391613@qq.com'
 * @LastEditTime: 2025-10-10 14:47:49
 * @FilePath: \book-3d-show\src\entity\Twin.ts
 * @Description: 这是默认设置,请设置`customMade`, 打开koroFileHeader查看配置 进行设置: https://github.com/OBKoro1/koro1FileHeader/wiki/%E9%85%8D%E7%BD%AE
 */
import * as THREE from "three"
import { OrbitControls } from "three/examples/jsm/controls/OrbitControls.js"
import Helper from "src/utils/Helper"
import GUI from "three/examples/jsm/libs/lil-gui.module.min.js"
import TWEEN from "@tweenjs/tween.js"
import { BoBook } from "src/utils/BoBook"
import type { IBoBoBook, IBookBase } from "src/interfaces/ICBook"
import { isBoBoBook } from "src/interfaces/ICBook"
import { BookTypeEnum } from "src/enums/BookTypeEnum"
export class CreateTwin {
  scene: THREE.Scene
  camera: THREE.PerspectiveCamera
  renderer: THREE.WebGLRenderer
  controls: OrbitControls
  textureLoader: THREE.TextureLoader
  roundedSquare: THREE.Mesh = new THREE.Mesh()
  helper: Helper = null as unknown as Helper
  gui: GUI = new GUI()

  book_width = 0
  book_height = 0
  book_depth = 0
  book_total = 0

  constructor(params = { helperBool: true }) {
    const {
      helperBool = true, //默认创建辅助开发工具
    } = params

    // 定义属性
    const width = window.innerWidth //宽度
    const height = window.innerHeight //高度

    // 创建纹理加载器
    this.textureLoader = new THREE.TextureLoader()
    this.scene = new THREE.Scene()
    this.camera = new THREE.PerspectiveCamera(45, width / height, 0.01, 6000)
    this.renderer = new THREE.WebGLRenderer({
      antialias: true, // 抗锯齿
      logarithmicDepthBuffer: true, //优化深度缓冲区精度
    })
    this.renderer.setPixelRatio(window.devicePixelRatio) // 设置 像素比率
    this.renderer.setSize(width, height) //设置three.js渲染区域的尺寸(像素px)
    this.camera.position.set(512, 512, 2000) // 设置相机位置

    document.body.appendChild(this.renderer.domElement)

    // 环境光
    const light = this.init_light()
    this.scene.add(light)
    // 创建初始圆角正方形

    // 相机控件
    this.controls = new OrbitControls(this.camera, this.renderer.domElement)
    this.controls.target.set(512, 512, 0)
    this.controls.update()
    if (helperBool) {
      this.helper = new Helper(this.scene, light)
      this.gui = this.helper.gui
    }
    window.addEventListener("resize", () => {
      this.renderer.setSize(window.innerWidth, window.innerHeight)
      this.camera.aspect = window.innerWidth / window.innerHeight
      this.camera.updateProjectionMatrix() // 更新矩阵面
    })

    // 渲染循环
    this.renderer.setAnimationLoop(() => {
      TWEEN.update()
      if (helperBool) this.helper.stats.update()

      // 光照位置随着镜头位置发生改变
      light.position.set(
        this.camera.position.x,
        this.camera.position.y,
        this.camera.position.z
      )

      this.renderer.render(this.scene, this.camera)
    })
    this.renderer.setClearColor(0xffffff)
  }

  greate_book(data: IBookBase | IBoBoBook, btype: BookTypeEnum) {
    this.book_total = data.total
    this.book_depth = data.depth
    if (isBoBoBook(data) && btype === BookTypeEnum.BoBo) {
      const book = new BoBook(data)
      const pages = book.book_group
      this.scene.add(pages)
    }
  }

  init_light() {
    const spotLight = new THREE.SpotLight(0xffffff, 3)
    // const ambient = new THREE.AmbientLight(0xffffff, 3)
    spotLight.position.set(500, 2000, 1000)
    spotLight.decay = 0.0
    return spotLight
  }

  loadColorTexture(path: string) {
    const texture = this.textureLoader.load(path)
    texture.colorSpace = THREE.SRGBColorSpace
    return texture
  }

  keyboard(key: string, obj: Record<string, number | string>) {
    if (key === "ArrowRight" || key === "ArrowLeft") {
      if (obj["angle"]) {
        this.turn_page(key, {
          angle: Number(obj["angle"]),
          page_no: Number(obj["page_no"]),
        })
      }
    }
  }

  turn_page = (
    key: "ArrowRight" | "ArrowLeft",
    config = { angle: Math.PI / 1, page_no: 0 }
  ) => {
    // 向右翻页
    if (key == "ArrowRight" && config.page_no < this.book_total / 2) {
      for (let i = 0; i < config.page_no + 1; i++) {
        console.log(`page_${i}`)
        const page_group = this.scene.getObjectByName(`page_${i}`)
        if (page_group == undefined) continue
        // 翻转后的z的位置
        const flip_z =
          this.book_depth * (config.page_no + 3 / 2) +
          (config.page_no - i) * this.book_depth

        if (i == config.page_no) {
          // 翻转
          const rotate = { rotate_y: 0, z: page_group.position.z }
          new TWEEN.Tween(rotate)
            .to({ rotate_y: -config.angle, z: -flip_z }, 1500)
            .easing(TWEEN.Easing.Circular.InOut)
            .onUpdate(function (obj) {
              page_group.rotation.y = obj.rotate_y
              page_group.position.z = obj.z
            })
            .start()

          break
        } else {
          new TWEEN.Tween(page_group.position)
            .easing(TWEEN.Easing.Cubic.In)
            .to(
              {
                z: -flip_z,
              },
              800
            )
            .start()
        }
      }
    }
    // 向左翻页
    else if (key == "ArrowLeft" && config.page_no > 0) {
      config.page_no -= 1

      for (let i = 0; i < config.page_no + 1; i++) {
        // 根据ID查找 group
        const page_group = this.scene.getObjectByName(`page_${i}`)
        if (page_group == undefined) continue

        if (i == config.page_no) {
          // 右边的位移
          const flip_z = config.page_no * this.book_depth + this.book_depth
          const rotate = { rotate_y: 0, z: page_group.position.z }

          new TWEEN.Tween(rotate)
            .to({ rotate_y: 2 * Math.PI - config.angle, z: -flip_z }, 1000)
            .easing(TWEEN.Easing.Circular.InOut)
            .onUpdate(function (obj) {
              page_group.rotation.y = config.angle + obj.rotate_y
              page_group.position.z = obj.z
            })
            .start()
          break
        } else {
          new TWEEN.Tween(page_group.position)
            .easing(TWEEN.Easing.Cubic.Out)
            .to(
              {
                z: -(
                  this.book_depth * (config.page_no + 3 / 2) +
                  (config.page_no - i) * this.book_depth -
                  2 * this.book_depth -
                  this.book_depth / 2
                ),
              },
              1200
            )
            .start()
        }
      }
    }
  }
}
